/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024.
 *
 * Description: The header file provides C preprocessor macros for use of
 * the ARMv8.3-PAuth extension in C and C++ code.
 * Author: wanghuizhao
 * Create: 2024-5-30
 */
#ifndef RTOS_PAUTH_H
#define RTOS_PAUTH_H

#ifdef CONFIG_RTOS_PAC_CFI_KERNEL
/**
 * Strips a Pointer Authentication Code.
 *
 * This macro removes any Pointer Authentication Code from a pointer value.
 *
 * @param type pointer type, @c d for data or @c i for instruction
 * @param addr pointer value to strip the PAC from
 *
 * @return the original unauthenticated pointer value
 */
#define pauth_strip(type, addr) \
({ \
	typeof(addr) __addr = (addr); \
\
	asm ("xpac" #type " %0\n" : "+r" (__addr)); \
	__addr; \
})

/**
 * @defgroup pac_internals Pointer Authentication internal macros
 * @{
 */
#define pauth_common(prefix, type, key, addr, mod) \
({ \
	typeof(addr) __addr = (addr); \
	unsigned long __mod = (unsigned long)(mod); \
\
	if (__builtin_constant_p(mod) && (__mod == 0)) \
		asm (#prefix #type "z" #key " %0\n" : "+r" (__addr)); \
	else \
		asm (#prefix #type #key " %0, %1\n" : "+r" (__addr) : "r" (__mod)); \
	__addr; \
})

/**
 * Wrapper for @c PACIA instruction.
 *
 * Signs a pointer with Instruction A key.
 */
#define pauth_pacia(addr, mod)	pauth_common(pac, i, a, addr, mod)

/**
 * Wrapper for @c PACIB instruction.
 *
 * Signs a pointer with Instruction B key.
 */
#define pauth_pacib(addr, mod)	pauth_common(pac, i, b, addr, mod)

/**
 * Wrapper for @c XPACD instruction.
 *
 * Strips the authentication code from a data pointer.
 */
#define pauth_xpacd(addr)		pauth_strip(d, addr)

/**
 * Wrapper for @c XPACI instruction.
 *
 * Strips the authentication code from an instruction pointer.
 */
#define pauth_xpaci(addr)		pauth_strip(i, addr)

#ifdef CONFIG_RTOS_PAC_FORWARD_CFI_BKEY
#define rtos_pac_forward(addr, mod)	pauth_pacib(addr, mod)
#else
#define rtos_pac_forward(addr, mod)	pauth_pacia(addr, mod)
#endif

#ifdef CONFIG_RTOS_PAC_BACKWARD_CFI_AKEY
#define rtos_pac_backward(addr, mod)	pauth_pacia(addr, mod)
#else
#define rtos_pac_backward(addr, mod)	pauth_pacib(addr, mod)
#endif

#else
#define rtos_pac_forward(addr, mod)	(addr)
#define rtos_pac_backward(addr, mod)	(addr)
#define pauth_xpaci(addr)	(addr)

#endif

#endif
